import { Duplex, Readable } from "stream";
import { CDNClient } from "./CDNClient";
import { CDNClientConfig } from "./CDNConfigs";
import COS from "cos-nodejs-sdk-v5";
import fs from "fs"

export class COSCDNClient implements CDNClient {
	constructor(config: CDNClientConfig) {
		this.setConfig(config)
		this.init();
	}
	protected config!: CDNClientConfig;
	setConfig(config: CDNClientConfig) {
		this.config = config;
	}

	init(): CDNClient {
		let config = this.config;
		let s3Client = this.s3Client;
		if (s3Client == null) {
			const s3Client = new COS({
				SecretId: config.accessKeyId, // 推荐使用环境变量获取；用户的 SecretId，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参考https://cloud.tencent.com/document/product/598/37140
				SecretKey: config.secretAccessKey, // 推荐使用环境变量获取；用户的 SecretKey，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参考https://cloud.tencent.com/document/product/598/37140
			});
			this.s3Client = s3Client
		}

		return this;
	}

	destroy(): Promise<boolean> {
		return Promise.resolve(true)
	}

	protected s3Client!: COS;
	async uploadFile(filepath: string, key: string, readFast: boolean): Promise<string> {
		let config = this.config;
		let s3Client = this.s3Client;

		let fstream = fs.createReadStream(filepath);
		let result = await new Promise<COS.PutObjectResult>((resolve, reject) => {
			s3Client.putObject({
				Bucket: config.bucket, /* 必须 */
				Region: config.region,    /* 必须 */
				Key: key,              /* 必须 */
				// StorageClass: readFast ? 'STANDARD' : 'STANDARD',
				Body: fstream, // 上传文件对象
				// onProgress: function (progressData) {
				// 	console.log(JSON.stringify(progressData));
				// }
			}, function (err, data) {
				// console.log(err || data);
				if (err) {
					console.error(err)
					console.log(`upload file failed: ${filepath}`)
					reject(err)
				} else {
					resolve(data)
				}
			})
		});
		return result?.Location
	}

	async uploadData(key: string, data: string | Buffer, readFast: boolean): Promise<string> {
		let config = this.config;
		let s3Client = this.s3Client;

		let result = await new Promise<COS.PutObjectResult>((resolve, reject) => {
			s3Client.putObject({
				Bucket: config.bucket, /* 必须 */
				Region: config.region,    /* 必须 */
				Key: key,              /* 必须 */
				// StorageClass: readFast ? 'STANDARD' : 'STANDARD',
				Body: data, // 上传文件对象
				// onProgress: function (progressData) {
				// 	console.log(JSON.stringify(progressData));
				// }
			}, function (err, data) {
				if (err) {
					console.error(err)
					console.log(`upload data failed: ${key}`)
					reject(err)
				} else {
					resolve(data)
				}
			})
		});

		return result?.Location
	}
	async fetchFile(key: string): Promise<Readable> {
		let config = this.config;
		let s3Client = this.s3Client;

		const result = await new Promise<Readable>((resolve, reject) => {
			s3Client.getObject({
				Bucket: config.bucket, /* 必须 */
				Region: config.region,    /* 必须 */
				Key: key,              /* 必须 */
			}, function (err, data) {
				if (err) {
					console.error(err)
					console.log(`fetch file failed: ${key}`)
					reject(err)
				} else {
					resolve(Readable.from(data.Body))
				}
			});
		})

		return result
	}
	async isExistObject(key: string): Promise<boolean> {
		let s3Client = this.s3Client;
		let config = this.config;

		var isFileExist = true;
		try {
			const existResult = await s3Client.headObject({
				Bucket: config.bucket, /* 必须 */
				Region: config.region,    /* 必须 */
				Key: key,              /* 必须 */
			});
			if (existResult.statusCode == 404) {
				isFileExist = false;
			}
		} catch (ex: any) {
			if (ex?.statusCode == 404) {
				isFileExist = false;
				console.log(`key-status:${ex.statusCode}`)
			}
		}
		return isFileExist;
	}

}
